package com.idea.relax.datascope;

import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.idea.relax.datascope.annotation.DataScope;
import com.idea.relax.datascope.auth.IAuthUserService;
import com.idea.relax.mybatis.interceptor.QueryInterceptor;
import com.idea.relax.tool.core.Func;
import com.idea.relax.tool.core.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Method;
import java.util.stream.Stream;


/**
 * mybatis 数据权限拦截器
 */
@Slf4j
@RequiredArgsConstructor
@SuppressWarnings({"rawtypes"})
public class DataScopeInterceptor implements QueryInterceptor {

	private final IAuthUserService authUserService;

	private final DataScopeConditionProcessor dataScopeConditionProcessor;

	@Override
	@SneakyThrows
	public void intercept(Executor executor, MappedStatement ms, Object parameter,
						  RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

		if (Func.isEmpty(authUserService.userOnline())) {
			return;
		}

		if (SqlCommandType.SELECT != ms.getSqlCommandType()) {
			return;
		}

		//获取拦截到的SQL
		String targetSql = boundSql.getSql();
		//获取mapper名称
		String mapperId = ms.getId();
		String className = mapperId.substring(0, mapperId.lastIndexOf("."));
		//获取方法名
		String methodName = mapperId.substring(mapperId.lastIndexOf(".") + 1);
		Method[] methods = Class.forName(className).getMethods();
		Stream.of(methods).filter(method -> StringUtil.eq(method.getName(), methodName))
			.forEach(method -> {
				DataScope annotation = method.getAnnotation(DataScope.class);
				if (null != annotation) {
					DataScopeEnum type = annotation.type();
					String column = annotation.column();
					String sql = dataScopeConditionProcessor.getCondition(type, column, boundSql, targetSql);
					if (!StringUtil.isBlank(sql)) {
						PluginUtils.MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql);
						mpBoundSql.sql(sql);
					}
				}
			});
	}

	@Override
	public int getOrder() {
		return 0;
	}
}
